package com.examination.system.instructor.dao.mysql;


import com.examination.framework.utils.DynamicSqlUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.ibatis.builder.annotation.ProviderContext;
import org.apache.ibatis.jdbc.SQL;
import org.apache.logging.log4j.message.StringFormattedMessage;

import javax.persistence.Column;
import javax.persistence.Id;
import javax.persistence.Table;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author 寇淇芮
 * @Date 2019/10/14 21:50
 */
public class BaseDynamicSqlProvider<T>  {
    public String saver(T entity,ProviderContext providerContext) throws IllegalAccessException {
        /**
         * 1 %s  表名
         * 2.%s  字段
         * 3 %s   值
         */
        return String.format("INSERT INTO %s %s values %s", DynamicSqlUtil.getTableName(providerContext),this.allField(entity),this.allValue(entity));
    }

    /**
     *
     * @param entity
     * @return
     */
    private String allValue(T entity) throws IllegalAccessException {
        String fieIdAllValue = "";
        String value ="";
        List<Field> fieldList= this.getAllFields(entity.getClass());
        for (Field item : fieldList) {
            item.setAccessible(true);
            value = String.valueOf(item.get(entity));
            if(value!=null && StringUtils.isNotEmpty(value)){
                fieIdAllValue = fieIdAllValue+ "#{"+item.getName()+"},";
            }
        }
        if(!fieIdAllValue.equals("")){
            fieIdAllValue = "("+fieIdAllValue.substring(0,fieIdAllValue.length()-1)+")";
        }
        return fieIdAllValue;
    }

    /**
     *
     * @param entity
     * @return
     * @throws IllegalAccessException
     */
    private String allField(T entity) throws IllegalAccessException {
        String fieIdAllName = "";
        String value ="";
        List<Field> fieldList= this.getAllFields(entity.getClass());
        for (Field item: fieldList) {
            item.setAccessible(true);
             value = String.valueOf(item.get(entity));
             if(StringUtils.isNotEmpty(value)){
                 fieIdAllName = fieIdAllName+ item.getAnnotation(Column.class).name()+",";
             }
        }
        if(!fieIdAllName.equals("")){
            fieIdAllName = "("+fieIdAllName.substring(0,fieIdAllName.length()-1)+")";
        }
        return fieIdAllName;
    }

    /**
     *
     * @param providerContext
     * @retur
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     */
    public String selectById(ProviderContext providerContext) throws ClassNotFoundException, IllegalAccessException {
        return String.format("Select * from %s where %s = #{id} ", DynamicSqlUtil.getTableName(providerContext),getIdentification(providerContext));
    }

    /**
     * 获取标识ID的属性对应的值
     * @param providerContext
     * @return
     */
    private String getIdentification(ProviderContext providerContext) throws ClassNotFoundException, IllegalAccessException {
         //获取类所有的属性值
        //得到表名
        //Class  classList = this.getClassList(providerContext);
        //获取到了所有的属性'
        List<Field> fieldList = this.getAllFields(this.getClassList(providerContext));
        for (Field field:fieldList) {
            field.setAccessible(true);
            Id annotation = field.getAnnotation(Id.class);
           // field.getAnnotation(Column.class).name();
            if(annotation != null){
               return field.getAnnotation(Column.class).name();
            }
        }
        return "id";
    }

    private Class  getClassList(ProviderContext providerContext) throws ClassNotFoundException {

        /**
         * 而 “？”则属于类型通配符的一种
         *  providerContext.getMapperType() 返回的是 class<?> 对象
         *  class.getGenericInterfaces 返回实现接口信息的Type数组，包含泛型信息
         *
         */
        Type[] genericInterfaces = providerContext.getMapperType().getGenericInterfaces();
        if(genericInterfaces==null){
            return null;
        }
        //返回表示此类型实际类型参数的 Type 对象的数组
        Type[] actualTypeArguments = ((ParameterizedType) genericInterfaces[0]).getActualTypeArguments();
        if(actualTypeArguments.length==0){
            return null;
        }
        //com.examination.system.instructor.student.ext.TbStudentEssential
        //获取到胡所有包名 com.examination.system.instructor.student.ext.TbStudentEssential

         return Class.forName(actualTypeArguments[0].getTypeName());
    }

    public String pageselect(T entity, ProviderContext providerContext) throws IllegalAccessException {
        String tableName = DynamicSqlUtil.getTableName(providerContext);

        String wheres = this.getConditionalStatement(entity,"","AND  ");
        return wheres == null ?String.format("Select * from %s",tableName) : String.format("select * FROM %s WHERE %s",tableName,wheres);
    }
    public String selectAll(ProviderContext providerContext)   {
        return  String.format("Select * from %s ",DynamicSqlUtil.getTableName(providerContext));
    }



    /**
     * 更新语句
     * @param entity
     * @return
     * @throws ClassNotFoundException
     * @throws IllegalAccessException
     */
    public String update(T entity,String id, ProviderContext providerContext) throws ClassNotFoundException, IllegalAccessException {
        //表名NAme
        return String.format("UPDATE %s set %s where %s = #{id}",DynamicSqlUtil.getTableName(providerContext),getConditionalStatement( entity,"entity.",", "),this.getIdentification(providerContext));

    }


    /**
     * 根据id删除数据
     * @param providerContext
     * @return
     */
    public String delectById(ProviderContext providerContext) throws ClassNotFoundException, IllegalAccessException {
        return String.format("DELETE FROM %s WHERE %s=#{id}",DynamicSqlUtil.getTableName(providerContext),getIdentification(providerContext));
    }

    /**
     * 删除语句
     * @param entity
     * @return
     * @throws IllegalAccessException
     * @throws ClassNotFoundException
     */
    public String delete(T entity,ProviderContext providerContext ) throws IllegalAccessException, ClassNotFoundException {
        /**
         * getCanonicalName 获取到包的路径
         * getSimpleName   获取到的是类名
         */

        String  canonicalName = Class.forName(entity.getClass().getCanonicalName()).getAnnotation(Table.class).name();

        String wheres = this.getConditionalStatement(entity,"","AND  ");

        return wheres == null || "".equals(wheres)?String.format("DELETE FROM %s", canonicalName):String.format("DELETE FROM %s WHERE  %s", canonicalName, wheres);
    }

    /**
     * 获取条件语句
     * @param entity
     * @return
     */
    private String getWhere(T entity) throws IllegalAccessException {
        return getConditionalStatement(entity,"entity.","AND ");
    }

    private String  getConditionalStatement(T entity,String param,String linkSymbol) throws IllegalAccessException {
        Object value;
        String   conditional = "";

        if(entity == null){
            return null;
        }

        //获取到了所有的属性
        List<Field> fieldList = this.getAllFields(entity.getClass());
        for (Field field : fieldList) {
            //强制开启访问类属性 值
                field.setAccessible(true);
            value = field.get(entity);
            if(value instanceof Integer){
                continue;
            }
            if (   value != null &&field.getAnnotation(Column.class)!=null ) {

                conditional   = conditional + field.getAnnotation(Column.class).name() + "=#{"+param +  field.getName() + "}  " + linkSymbol ;
            }
        }
        return  "".equals(conditional) ? null : conditional.substring(0, conditional.length() - linkSymbol.length()).trim();
    }


    private List<Field> getAllFields(Class<?> aClass ){
        //反射拿到对象

        /**
         * 创建一个数据保存数据
         */
        List<Field> fieldList = new CopyOnWriteArrayList<>();
        while (aClass != null){
            //fieldList.addAll(new ArrayList<>(Arrays.asList(aClass.getDeclaredFields())));
            /**
             * Arrays.asList == new ArrayList<>(a)
             *   public Field[] getDeclaredFields()
              */
            fieldList.addAll(new CopyOnWriteArrayList<>(Arrays.asList(aClass.getDeclaredFields())));
            //fieldList.addAll(new CopyOnWriteArrayList<>(aClass.getDeclaredFields()));
            aClass = aClass.getSuperclass();
        }
        return fieldList;
    }

}
